﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using vngoodlife.Singleton;
using vngoodlife.DTO;
using System.ComponentModel.DataAnnotations;
using vngoodlife.Util;
using System.IO;

namespace vngoodlife.Models
{
    public class Article_Validation
    {
        //[System.ComponentModel.DataAnnotations.MetadataType(typeof(vngoodlife.Models.Article_Validation))]
        [Required(ErrorMessage = "Tiêu đề Không được để trống.")]
        public string Title { get; set; }

        [Required(ErrorMessage = "Mô tả Không được để trống.")]
        public string Description { get; set; }

        [Required(ErrorMessage = "Nội dung Không được để trống.")]
        public string Content { get; set; }
    }

    public class ArticleModels
    {
        #region Backend

        internal void ChangeArticleVisible(int articleID, bool articleVisible)
        {
            Article article = DataSingleton.Instance.GetLinQContext().Articles.SingleOrDefault(u => u.ArticleID == articleID);
            article.ArticleVisible = (!articleVisible);
            DataSingleton.Instance.GetLinQContext().Articles.Context.SubmitChanges();
        }

        /// <summary>
        /// Delete a article by articleID
        /// </summary>
        /// <param name="articleID"></param>
        internal void DeleteArticle(int articleID, string path)
        {
            try
            {
                string LocalFile = path + DataSingleton.Instance.GetLinQContext().Articles.SingleOrDefault(u => u.ArticleID == articleID).Photo;
                    if (File.Exists(LocalFile))
                        File.Delete(LocalFile);
                DataSingleton.Instance.GetLinQContext().sp_DeleteArticle(articleID);

            }
            catch (Exception)
            {
                vngoodlife.DTO.General_dto.ClearCacheDataContext(DataSingleton.Instance.GetLinQContext());
                //DataSingleton.Instance.RefreshInstance();
            }
        }


        internal IQueryable<MenuList> GetArticleType()
        {
            return DataSingleton.Instance.GetLinQContext().MenuLists.Where(u => u.MenuTypeID == "ART" && u.MenuListID != 100);
        }


        internal bool ArticleEdit(Article art, string adminName)
        {
            try
            {
                art.Title = art.Title.Trim();
                art.Description = art.Description.Trim();
                art.AdminName = adminName;
                art.UpdateDate = DateTime.Now;

                DataSingleton.Instance.GetLinQContext().Articles.Context.SubmitChanges();

            }
            catch (Exception)
            {
                //DataSingleton.Instance.RefreshInstance();
                vngoodlife.DTO.General_dto.ClearCacheDataContext(DataSingleton.Instance.GetLinQContext());
                return false;
            }
            return true;
        }

        internal int ArticleCreate(Article art, string memberName, string adminName)
        {
            //try
            //{

                int re = DataSingleton.Instance.GetLinQContext().sp_ArticleInsert(memberName, art.ArtSubjectID,art.ArtStatusID,
                       art.Title.Trim(), art.Description.Trim(), art.Content, art.Photo, art.Focus, art.IsVideo, art.IsImage, adminName);

                return re;
            //}
            //catch (Exception)
            //{
            //    DataSingleton.Instance.RefreshInstance();
            //    return 0;
            //}
        }


        internal IQueryable<Article> GetFilterArticle_BackEnd(string statusID, string articleTypeID, string amount)
        {
            int _statusID = 0; int _articleTypeID = 0; int _amount = 0;
            if (statusID != "")
            {
                _statusID = Convert.ToInt16(statusID);
            }

            if (articleTypeID != "")
            {
                _articleTypeID = Convert.ToInt16(articleTypeID);
            }

            if (amount != "")
            {
                _amount = Convert.ToInt16(amount);
            }


            if (_articleTypeID != 0 && _statusID != 0 && _amount != 0)//1
            {
                IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                            .Where(u => (u.Superior == _articleTypeID || u.MenuListID == _articleTypeID)
                                                   && u.MenuVisible == true)
                                            .Select(u => u.MenuListID);
                IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();


                //IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                //                 .Where(u => u.ArticleTypeID == _articleTypeID).Select(u => u.ArticleID).Distinct();

                return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => articleIDList.Any(y => y == u.ArticleID)
                                        && u.ArtStatusID == _statusID
                                       )
                                 .OrderByDescending(u => u.ArticleID).Take(_amount);
            }
            else if (_articleTypeID == 0 && _statusID == 0 && _amount == 0)//2
            {
                return DataSingleton.Instance.GetLinQContext().Articles.OrderByDescending(u => u.ArticleID);
            }
            else if (_statusID == 0 && _articleTypeID != 0 && _amount != 0)//3
            {
                IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                            .Where(u => (u.Superior == _articleTypeID || u.MenuListID == _articleTypeID)
                                                   && u.MenuVisible == true)
                                            .Select(u => u.MenuListID);
                IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();

                //IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                //                 .Where(u => u.ArticleTypeID == _articleTypeID).Select(u => u.ArticleID).Distinct();

                return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => articleIDList.Any(y => y == u.ArticleID)
                                       )
                                 .OrderByDescending(u => u.ArticleID).Take(_amount);
            }
            else if (_statusID != 0 && _articleTypeID == 0 && _amount != 0)//4
            {
                return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(u => u.ArtStatusID == _statusID)
                                 .OrderByDescending(u => u.ArticleID).Take(_amount);
            }
            else if (_statusID != 0 && _articleTypeID != 0 && _amount == 0)//5
            {
                IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                            .Where(u => (u.Superior == _articleTypeID || u.MenuListID == _articleTypeID)
                                                   && u.MenuVisible == true)
                                            .Select(u => u.MenuListID);
                IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();


                //IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                //                 .Where(u => u.ArticleTypeID == _articleTypeID).Select(u => u.ArticleID).Distinct();

                return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => articleIDList.Any(y => y == u.ArticleID)
                                             && u.ArtStatusID == _statusID
                                       )
                                 .OrderByDescending(u => u.ArticleID);
            }
            else if (_statusID == 0 && _articleTypeID == 0 && _amount != 0)//6
            {
                return DataSingleton.Instance.GetLinQContext().Articles.OrderByDescending(u => u.ArticleID).Take(_amount);
            }
            else if (_statusID != 0 && _articleTypeID == 0 && _amount == 0)//7
            {
                return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(u => u.ArtStatusID == _statusID).OrderByDescending(u => u.ArticleID);
            }
            else
            {
                IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                            .Where(u => (u.Superior == _articleTypeID || u.MenuListID == _articleTypeID)
                                                   && u.MenuVisible == true)
                                            .Select(u => u.MenuListID);
                IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();

                //IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                //                 .Where(u => u.ArticleTypeID == _articleTypeID).Select(u => u.ArticleID).Distinct();

                return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(u => articleIDList.Any(y => y == u.ArticleID))
                                 .OrderByDescending(u => u.ArticleID);
            }
       
        }

        #endregion

        #region frontend

        /// <summary>
        /// used in frontend article list, return the latest article in a type
        /// </summary>
        /// <param name="menuListID"></param>
        /// <returns></returns>
        internal IQueryable<Article> GetLatestArticlesByType_Frontend(int menuListID, int amount, int currentArticleID)
        {
            IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                        .Where(u => (u.Superior == menuListID || u.MenuListID == menuListID) && u.MenuVisible == true)
                                        .Select(u => u.MenuListID);

            IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();

            if (currentArticleID == 0)
            {
                return DataSingleton.Instance.GetLinQContext().Articles
                                     .Where(
                                            u => articleIDList.Any(y => y == u.ArticleID)
                                            && u.ArticleVisible == true
                                            && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                           )
                                     .OrderByDescending(u => u.ArticleID).Take(amount);
            }
            else
            {
                return DataSingleton.Instance.GetLinQContext().Articles
                                     .Where(
                                            u => articleIDList.Any(y => y == u.ArticleID)
                                            && u.ArticleVisible == true
                                            && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                            && u.ArticleID != currentArticleID
                                           )
                                     .OrderByDescending(u => u.ArticleID).Take(amount);
            }
        }


        /// <summary>
        /// used in frontend article list with paging
        /// </summary>
        /// <param name="menuListID"></param>
        /// <returns></returns>
        internal IQueryable<Article> GetArticlesByType_Frontend(int menuListID, int currentPage, int ArticlePageStep)
        {
            int startRowIndex = (currentPage - 1) * ArticlePageStep;
            IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                        .Where(u => (u.Superior == menuListID || u.MenuListID == menuListID) && u.MenuVisible == true)
                                        .Select(u => u.MenuListID);

            IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();

            return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => articleIDList.Any(y => y == u.ArticleID)
                                        && u.ArticleVisible == true
                                        && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                       )
                                 .OrderByDescending(u => u.ArticleID).Skip(startRowIndex).Take(ArticlePageStep);
        }

        /// <summary>
        /// use in ArticleListFrontend, get total number of article of a type
        /// </summary>
        /// <param name="menuListID"></param>
        /// <returns></returns>
        internal int Frontend_GetTotalArticleByType(int menuListID)
        {
            IQueryable<int> sub = DataSingleton.Instance.GetLinQContext().MenuLists
                                        .Where(u => (u.Superior == menuListID || u.MenuListID == menuListID) && u.MenuVisible == true)
                                        .Select(u => u.MenuListID);

            return DataSingleton.Instance.GetLinQContext().ArticleViews
                                 .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct().Count();

            //IQueryable<int> articleIDList = DataSingleton.Instance.GetLinQContext().ArticleViews
            //                     .Where(u => sub.Contains(u.ArticleTypeID)).Select(u => u.ArticleID).Distinct();

            //return DataSingleton.Instance.GetLinQContext().Articles
            //                     .Where(
            //                            u => articleIDList.Any(y => y == u.ArticleID)
            //                            && u.ArticleVisible == true
            //                            && (u.ArtStatusID == 3|| u.ArtStatusID == 4)
            //                           )
            //                     .Count();
        }


        /// <summary>
        /// Get Type of a article
        /// </summary>
        /// <param name="articleID"></param>
        /// <returns></returns>
        internal int GetArticleTypeOfArticle(int articleID)
        {
            try
            {
                return DataSingleton.Instance.GetLinQContext().TypesOfArticles.Where(t => t.ArticleID == articleID).OrderByDescending(t=>t.ArticleTypeID).First()
                    .ArticleTypeID;
            }
            catch (Exception)
            {
                return 0;
            }
            
        }


        /// <summary>
        /// Get all available article for home page
        /// </summary>
        internal IQueryable<Article> GetArticleForHomePage(int page)
        {
                return DataSingleton.Instance.GetLinQContext().Articles.
                    Where(a => a.ArticleVisible == true 
                                && (a.ArtStatusID == 3 || a.ArtStatusID == 4)
                                && !DataSingleton._listNewArticleIDsOfEachArticleType.Contains(a.ArticleID) 
                                && !a.TypesOfArticles.Any(x => x.ArticleTypeID == 138))
                    .OrderByDescending(a => a.ArticleID).OrderByDescending(a => a.ArtStatusID)
                    .Skip((page - 1) * ConstantClass.ArticleHomePageStep)
                    .Take(ConstantClass.ArticleHomePageStep);
        }

        /// <summary>
        /// get number article according to tag.
        /// </summary>
        /// <param name="tagID"></param>
        /// <returns></returns>
        internal int Frontend_GetTotalArticleByTags(int tagID)
        {
            //IQueryable<int> art = DataSingleton.Instance.GetLinQContext().Article_Tags
            //                      .Where(u => (u.TagsID == tagID)).Select(u => u.ArticleID);
            
            //return DataSingleton.Instance.GetLinQContext().Articles
            //                     .Where(
            //                            u => art.Contains(u.ArticleID)
            //                            && u.ArticleVisible == true
            //                            && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
            //                           )
            //                     .Count();

            return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => u.Article_Tags.Select(x => x.TagsID).Contains(tagID)
                                        && u.ArticleVisible == true
                                        && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                       )
                                 .Count();
        }

        /// <summary>
        /// get number article according to subject.
        /// </summary>
        /// <param name="tagID"></param>
        /// <returns></returns>
        internal int Frontend_GetTotalArticleBySubjects(int subID)
        {
            return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => u.ArtSubjectID == subID
                                        && u.ArticleVisible == true
                                        && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                       )
                                 .Count();
        }


        internal IQueryable<Article> GetArticlesByTag_Frontend(int tagID, int currentPage, int PageStep)
        {
            int startRowIndex = (Convert.ToInt16(currentPage) - 1) * PageStep;

            //IQueryable<int> art = DataSingleton.Instance.GetLinQContext().Article_Tags
            //                      .Where(u => (u.TagsID == tagID)).Select(u => u.ArticleID);

            //return DataSingleton.Instance.GetLinQContext().Articles
            //                     .Where(
            //                            u => art.Contains(u.ArticleID)
            //                            && u.ArticleVisible == true
            //                            && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
            //                           )
            //                     .OrderByDescending(u => u.ArticleID).Skip(startRowIndex).Take(PageStep);

            return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => u.Article_Tags.Select(x => x.TagsID).Contains(tagID)
                                        && u.ArticleVisible == true
                                        && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                       )
                                 .OrderByDescending(u => u.ArticleID).Skip(startRowIndex).Take(PageStep);
        }


        internal IQueryable<Article> GetArticlesBySubject_Frontend(int subID, int currentPage, int PageStep)
        {
            int startRowIndex = (Convert.ToInt16(currentPage) - 1) * PageStep;

            return DataSingleton.Instance.GetLinQContext().Articles
                                 .Where(
                                        u => u.ArtSubjectID == subID
                                        && u.ArticleVisible == true
                                        && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                       )
                                 .OrderByDescending(u => u.ArticleID).Skip(startRowIndex).Take(PageStep);
        }


        internal void GainViewNumber(int articleID)
        {
            try
            {
                //DataSingleton.Instance.GetLinQContext().Connection.Open();
                Article article = DataSingleton.Instance.GetLinQContext().Articles.SingleOrDefault(u => u.ArticleID == articleID);
                article.ViewNumber = article.ViewNumber + 1;
                DataSingleton.Instance.GetLinQContext().Articles.Context.SubmitChanges();
                //DataSingleton.Instance.GetLinQContext().Connection.Close();
            }
            catch (Exception)
            {
                //DataSingleton.Instance.RefreshInstance();
                vngoodlife.DTO.General_dto.ClearCacheDataContext(DataSingleton.Instance.GetLinQContext());
            }
        }

        /// <summary>
        /// get most viewed article
        /// </summary>
        /// <param name="amount">number of article </param>
        /// <param name="day"> in "day" days Ex. day = 12 : 12 days ago. </param>
        /// <returns></returns>
        internal IQueryable<Article> GetMostviewedArticles_Frontend(int amount, int day)
        {
            return DataSingleton.Instance.GetLinQContext().Articles
                                         .Where(
                                                u => u.ArticleVisible == true
                                                && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                                && DateTime.Now.AddDays(-day) < u.CreateDate
                                              //  && !u.TypesOfArticles.Any(x=>x.ArticleTypeID==138)
                                                )
                                         .OrderByDescending(u => u.ViewNumber).Take(amount);
        }

        /// <summary>
        /// Ex: amount = 5, number = 20 means get 5 random articles in 20 latest article. use in frontend
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="number"></param>
        /// <returns></returns>
        internal IEnumerable<Article> GetRecentArticles_Frontend(int amount, int number)
        {
            List<Article> articleTemp = new List<Article> { };
            var rand = new Random();
            IEnumerable<Article> allArticles = DataSingleton.Instance.GetLinQContext().Articles
                                                                 .Where(
                                                                     u => u.ArticleVisible == true
                                                                     && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                                                     && !u.TypesOfArticles.Any(x => x.ArticleTypeID == 138)
                                                                 ).OrderByDescending(u=>u.ArticleID).Take(number);
            
            while (articleTemp.Count() < amount) 
            {
                var x = allArticles.Skip(rand.Next(number-1)).First();

                if (x != null && !articleTemp.Contains(x))
                {
                    articleTemp.Add(x);
                }
            }

            return articleTemp;
        }


        /// <summary>
        /// Ex: amount = 5, 
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="number"></param>
        /// <returns></returns>
        internal IEnumerable<Article> RandomArticles_Frontend(int amount)
        {
           
           
            List<Article> randomArticle = new List<Article> { };
            var rand = new Random();
            int lastID = DataSingleton.Instance.GetLinQContext().Articles.OrderByDescending(u => u.ArticleID).First().ArticleID;
            while (randomArticle.Count() < amount)
            {
                var x = DataSingleton.Instance.GetLinQContext().Articles
                        .SingleOrDefault(
                                  u => u.ArticleVisible == true
                                  && (u.ArtStatusID == 3 || u.ArtStatusID == 4)
                                  && !u.TypesOfArticles.Any(k => k.ArticleTypeID == 138)
                                  && u.ArticleID == rand.Next(lastID)
                                 );

                if (x != null && !randomArticle.Contains(x))
                {
                    randomArticle.Add(x);
                }
            }
           

            return randomArticle;
        }

        #endregion


    }
}